﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using System;
using NJamb.Specifications;
using Stile.Patterns.SelfDescribingPredicates;
using Stile.Patterns.SelfDescribingPredicates.Evaluators;
using Stile.Readability;
#endregion

namespace NJamb.Parser.SpecificationBuilders.SubjectIs.Extensions
{
    public static class IsNumericExtensions
    {
        public static TSpecifies Infinity<TSpecifies>(this IFluentIs<double, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<double>
        {
            return Make(collaboratingIs, double.IsInfinity, "infinity");
        }

        public static TSpecifies Infinity<TSpecifies>(this IFluentIs<float, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<float>
        {
            return Make(collaboratingIs, float.IsInfinity, "infinity");
        }

        public static TSpecifies NaN<TSpecifies>(this IFluentIs<double, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<double>
        {
            return Make(collaboratingIs, double.IsNaN, "NaN");
        }

        public static TSpecifies NaN<TSpecifies>(this IFluentIs<float, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<float>
        {
            return Make(collaboratingIs, float.IsNaN, "NaN");
        }

        public static TSpecifies NegativeInfinity<TSpecifies>(this IFluentIs<double, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<double>
        {
            return Make(collaboratingIs, double.IsNegativeInfinity, "negative infinity");
        }

        public static TSpecifies NegativeInfinity<TSpecifies>(this IFluentIs<float, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<float>
        {
            return Make(collaboratingIs, float.IsNegativeInfinity, "negative infinity");
        }

        public static TSpecifies PositiveInfinity<TSpecifies>(this IFluentIs<double, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<double>
        {
            return Make(collaboratingIs, double.IsPositiveInfinity, "positive infinity");
        }

        public static TSpecifies PositiveInfinity<TSpecifies>(this IFluentIs<float, TSpecifies> collaboratingIs)
            where TSpecifies : class, ISpecification<float>
        {
            return Make(collaboratingIs, float.IsPositiveInfinity, "positive infinity");
        }

        private static TSpecifies Make<TNumber, TSpecifies>(IFluentIs<TNumber, TSpecifies> fluentIs,
            Func<TNumber, bool> func,
            string description) where TSpecifies : class, ISpecification<TNumber>
        {
            VerbTensePair wouldBeButWas = VerbTensePair.WouldBeButWas;

            var evaluator =
                new Evaluator<TNumber>(new ExpectedClause<TNumber>(wouldBeButWas, x => fluentIs.Xray.Negated + description),
                    new ActualClause<TNumber>(wouldBeButWas, x => x.ToDebugString()),
                    func);
            TSpecifies specifies = fluentIs.Xray.SpecificationBuilder.Specify(evaluator);
            return specifies;
        }
    }
}
